package com.gxp.system.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.gxp.common.core.text.Convert;
import com.gxp.common.utils.DictUtils;
import com.gxp.common.utils.StringUtils;
import com.gxp.system.domain.ZkAutoExpinfo;
import com.gxp.system.domain.ZkInstrument;
import com.gxp.system.domain.dto.ZkAutoExpinfoDto;
import com.gxp.system.domain.dto.exp.AutoExpListDto;
import com.gxp.system.domain.dto.exp.Automation;
import com.gxp.system.domain.dto.exp.Exp;
import com.gxp.system.domain.dto.exp.Slot;
import com.gxp.system.mapper.ZkAutoExpinfoMapper;
import com.gxp.system.mapper.ZkInstrumentMapper;
import com.gxp.system.service.IZkAutoExpinfoService;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自动化实验Service业务层处理
 * 
 * @author zh
 * @date 2024-03-20
 */
@Service
public class ZkAutoExpinfoServiceImpl implements IZkAutoExpinfoService 
{

    private static final Logger log = LoggerFactory.getLogger(ZkAutoExpinfoServiceImpl.class);

    @Autowired
    private ZkAutoExpinfoMapper zkAutoExpinfoMapper;
    @Autowired
    private ZkInstrumentMapper instrumentMapper;

    /**
     * 查询自动化实验
     * 
     * @param autoexpId 自动化实验主键
     * @return 自动化实验
     */
    @Override
    public ZkAutoExpinfo selectZkAutoExpinfoByAutoexpId(Long autoexpId)
    {
        return zkAutoExpinfoMapper.selectZkAutoExpinfoByAutoexpId(autoexpId);
    }

    /**
     * 查询自动化实验列表
     * 
     * @param zkAutoExpinfo 自动化实验
     * @return 自动化实验
     */
    @Override
    public List<ZkAutoExpinfo> selectZkAutoExpinfoList(ZkAutoExpinfo zkAutoExpinfo)
    {
        return zkAutoExpinfoMapper.selectZkAutoExpinfoList(zkAutoExpinfo);
    }

    /**
     * 新增自动化实验
     * 
     * @param zkAutoExpinfo 自动化实验
     * @return 结果
     */
    @Override
    public int insertZkAutoExpinfo(ZkAutoExpinfo zkAutoExpinfo)
    {
        return zkAutoExpinfoMapper.insertZkAutoExpinfo(zkAutoExpinfo);
    }

    /**
     * 修改自动化实验
     * 
     * @param zkAutoExpinfo 自动化实验
     * @return 结果
     */
    @Override
    public int updateZkAutoExpinfo(ZkAutoExpinfo zkAutoExpinfo)
    {
        return zkAutoExpinfoMapper.updateZkAutoExpinfo(zkAutoExpinfo);
    }

    /**
     * 批量删除自动化实验
     * 
     * @param autoexpIds 需要删除的自动化实验主键
     * @return 结果
     */
    @Override
    public int deleteZkAutoExpinfoByAutoexpIds(String autoexpIds)
    {
        return zkAutoExpinfoMapper.deleteZkAutoExpinfoByAutoexpIds(Convert.toStrArray(autoexpIds));
    }

    /**
     * 删除自动化实验信息
     * 
     * @param autoexpId 自动化实验主键
     * @return 结果
     */
    @Override
    public int deleteZkAutoExpinfoByAutoexpId(Long autoexpId)
    {
        return zkAutoExpinfoMapper.deleteZkAutoExpinfoByAutoexpId(autoexpId);
    }

    /**
     * 查询自动化实验信息
     */
    @Override
    public List<ZkAutoExpinfoDto> selectZkAutoExpinfoByInstId(Long instId) {
        int sampleTotal = Math.toIntExact(instrumentMapper.selectZkInstrumentByInstId(instId).getSampleTotal());
        List<ZkAutoExpinfoDto> autoExpinfoDtos = new ArrayList<>();
        List<ZkAutoExpinfo> autoExpinfos = zkAutoExpinfoMapper.selectZkAutoExpinfoByInstId(instId);
        for (int i = 1; i <= sampleTotal; i++) {
            ZkAutoExpinfoDto autoExpinfoDto = new ZkAutoExpinfoDto();
            autoExpinfoDto.setSlot(i);
            int finalI = i;
            autoExpinfoDto.setAutoExpinfos(autoExpinfos.stream().filter(zkAutoExpinfo -> zkAutoExpinfo.getSlot() == finalI).collect(Collectors.toList()));
            autoExpinfoDto.setStatus(autoExpinfoDto.getAutoExpinfos().size()+"");
            autoExpinfoDtos.add(autoExpinfoDto);
        }
        return autoExpinfoDtos;
    }

    /**
     * 将SSJ上xml实验数据存到数据库
     * @param expinfoString
     * @return
     */
    @Override
    public boolean updateExpinfo(String expinfoString) {
        if(StringUtils.isNull(expinfoString)){
            return false;
        }
        // xmlString -> json.JSONObject
        org.json.JSONObject jsonObject = XML.toJSONObject(expinfoString);
        // json.JSONObject -> jsonString -> JSONObject(fastjson)
        JSONObject expinfojson = JSONObject.parseObject(jsonObject.toString());
        // JSONObject(fastjson) -> java对象
        AutoExpListDto autoExpListDto = expinfojson.toJavaObject(AutoExpListDto.class);
        List<ZkAutoExpinfo> expinfos = new ArrayList<>();
        if (getZkAutoExpinfos(autoExpListDto, expinfos)) {
            if(!expinfos.isEmpty()){
                //更新数据库
                update(autoExpListDto, expinfos);
            }
        }else {
            log.error("fail to update expinfo");
            return false;
        }
        return true;
    }

    @Override
    public List<ZkAutoExpinfo> selectAll() {
        return zkAutoExpinfoMapper.selectAll();
    }

    @Transactional
    public void update(AutoExpListDto autoExpListDto, List<ZkAutoExpinfo> expinfos) {
        // 根据hostId删除自动化实验数据
//        zkAutoExpinfoMapper.deleteByInstrument(autoExpListDto.getAutomation().getHostid());
        // 更新自动化实验数据
//        zkAutoExpinfoMapper.batchAutoExpinfos(expinfos);
        // 根据hostId找到expcode集合
        List<String> expcodesDatabase = zkAutoExpinfoMapper.selectZkAutoExpinfoByInstrument(autoExpListDto.getAutomation().getHostid())
                .stream().map(ZkAutoExpinfo::getExpCode).collect(Collectors.toList());
        // 数据库同步更新
        List<String> expcodesSSJ = expinfos.stream().map(ZkAutoExpinfo::getExpCode).collect(Collectors.toList());
        // 数据库有，SSJ没有，数据库删除
        List<String> codesRemove = expcodesDatabase.stream().filter(code -> !expcodesSSJ.contains(code)).collect(Collectors.toList());
        if(!StringUtils.isEmpty(codesRemove)){
            zkAutoExpinfoMapper.deleteByExpcodes(codesRemove.stream().toArray(String[]::new));
        }
        // 数据库没有， SSJ有， 数据库新增
        List<String> codeAdd = expcodesSSJ.stream().filter(code -> !expcodesDatabase.contains(code)).collect(Collectors.toList());
        if(!StringUtils.isEmpty(codeAdd)){
            zkAutoExpinfoMapper.batchAutoExpinfos(expinfos.stream().filter(expinfo -> codeAdd.contains(expinfo.getExpCode())).collect(Collectors.toList()));
        }
        // 其它的，更新数据库
        List<ZkAutoExpinfo> updateExpinfos = expinfos.stream().filter(expinfo -> !codeAdd.contains(expinfo.getExpCode())).collect(Collectors.toList());
        for (ZkAutoExpinfo updateExpinfo : updateExpinfos) {
            zkAutoExpinfoMapper.updateZkAutoExpinfoByExpcode(updateExpinfo);
        }
    }

    /**
     * AutoExpListDto -> List<ZkAutoExpinfo>
     */
    private boolean getZkAutoExpinfos(AutoExpListDto autoExpListDto, List<ZkAutoExpinfo> expinfos) {
        Automation automation = autoExpListDto.getAutomation();
        String hostid = automation.getHostid();
        List<ZkInstrument> instruments = instrumentMapper.selectZkInstrumentList(new ZkInstrument());
        List<ZkInstrument> filter = instruments.stream().filter(instrument -> instrument.getHostId().equals(hostid)).collect(Collectors.toList());
        if(filter.size() == 1){
            List<Slot> slots = automation.getSlot();
            for (Slot slot : slots) {
                if(slot.getExp() != null && !slot.getExp().isEmpty()){
                    for (Exp exp : slot.getExp()) {
                        ZkAutoExpinfo autoExpinfo = new ZkAutoExpinfo();
                        autoExpinfo.setInstId(filter.get(0).getInstId());
                        autoExpinfo.setSlot(slot.getNumber().intValue());
                        autoExpinfo.setExpCode(exp.getCode());
                        //swhz:11013|p1:11.0|np:44051|decplvl:40.0|frqohz1:0.0|ns:16|acqtime:3.99984896|nuc1:C13|tempstart:0.0|fq:0.0|d1:1.0|tempfinish:0.0|dectype:www|gain:30.0|decon:nnn|decon1:nnn|predelay:10.0|frqo1:0.0|acqfrq:11013.215859|frqo:6.0|sfrq1:125.7466632|dimension:1|arraymode:0|console:BIXI-I|plvl1:51.0|dectype1:www|sw:22.0221|acqmode:dqd|frqb1:125.7466632|sfrq:500.0887561|decplvl1:40.0|decpw1:40.0|pulseseq:s1pul30|frqb:500.0857556|magnet:AS400|dummyscan:2|probe:probehead|cs:0|frqohz:3000.51|lockfreq:76.766209|deadtime:30.0|decpw:40.0|solvent:CDCl3|nuc:H1|username:guest|
                        autoExpinfo.setExperiment(exp.getExperiment());
                        autoExpinfo.setGain(exp.getGain()?"1":"0");
                        autoExpinfo.setNo(exp.getFile());
                        autoExpinfo.setShim(exp.getShim()?"1":"0");
                        autoExpinfo.setSolvent(exp.getSolvent());
                        autoExpinfo.setParam(exp.getExpparams());
                        autoExpinfo.setEndTime(exp.getEnddate());
                        autoExpinfo.setStartTime(exp.getStartdate());
                        autoExpinfo.setAutoexpName(exp.getName());
                        String shimflag = exp.getShimflag();
                        String[] split = shimflag.split("\\|");
                        autoExpinfo.setStm("true".equals(split[0])?"1":"0");
                        autoExpinfo.setTitle(exp.getTitle());
                        autoExpinfo.setExpLock(exp.getLock()?"1":"0");
//                        autoExpinfo.setTempspin();
                        autoExpinfo.setUser(exp.getUser());
                        autoExpinfo.setStatus(DictUtils.getDictLabel("auto_exp_status",exp.getStatus()+""));
                        expinfos.add(autoExpinfo);
                    }
                }
            }
        }else {
            return false;
        }
        return true;
    }
}
